package com.landun.market.web;

import com.landun.market.exception.SystemException;
import com.landun.market.pojo.Constants;
import com.landun.market.pojo.enums.ResponseCode;
import com.landun.market.web.domain.ApiOut;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.util.Strings;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;

/**
 * 统一异常处理
 *
 * @author jiang.chuan
 * @date 2018-05-05
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @ResponseBody
    @ExceptionHandler(value = {Throwable.class, NoHandlerFoundException.class})
    public ApiOut handleThrowable(HttpServletRequest request, Throwable ex) {
        ResponseCode responseCode = ResponseCode.SYSTEM_ERROR;
        String message = ex.getMessage();
        Pair<String, String> debugMsgPair;
        if (ex instanceof SystemException) {
            SystemException exception = (SystemException) ex;
            if (null != exception.getResponseCode()) {
                responseCode = exception.getResponseCode();
                message = exception.getMessage();
            }
            debugMsgPair = getCause(ex);
            log.warn(String.format("LanDun: Code:%s-%s, Msg:%s", responseCode.name(), responseCode.code(), exception.getMessage()), exception);
        } else if (ex instanceof ServletRequestBindingException && StringUtils.contains(ex.getMessage(), Constants.TOKEN_PARA_NAME)) {
            debugMsgPair = Pair.of(ex.getMessage(), StringUtils.EMPTY);
            responseCode = ResponseCode.SYSTEM_ERROR;
            message = "请登录";
        } else {
            debugMsgPair = getCause(ex);
            log.warn("SYS:" + debugMsgPair.getLeft(), ex);
        }

        return new ApiOut.Builder<>().code(responseCode).message(message).debugMessage(debugMsgPair.getLeft()).build();
    }

    /**
     * 获取错误日志堆栈
     *
     * @param throwable
     * @return
     */
    private Pair<String, String> getCause(Throwable throwable) {
        if (null == throwable) {
            return Pair.of(StringUtils.EMPTY, StringUtils.EMPTY);
        }

        String message = throwable.getMessage(), fileName = "";
        if (Strings.isBlank(message)) {
            message = throwable.toString();
        }

        StackTraceElement[] stackTraceElements = throwable.getStackTrace();
        if (ArrayUtils.isNotEmpty(stackTraceElements)) {
            for (StackTraceElement stackTraceElement : stackTraceElements) {
                if (StringUtils.startsWithIgnoreCase(stackTraceElement.getClassName(), "com.landun")) {
                    fileName = stackTraceElement.getFileName();
                    message += "@" + stackTraceElement.toString();
                    break;
                }
            }
        }
        return Pair.of(message, fileName);
    }
}